using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Ideopuzzle
{
    public delegate void Press(MenuEntry entry);

    public abstract class MenuEntry
    {
        #region Fields

        public event Press OnPress;

        protected Vector2 position;
        public Vector2 scrollOffset;

        protected Rectangle rectangle;
        protected SpriteBatch sprite_batch;
        protected float alpha = 1.0f;

        #endregion

        #region Draw

        public abstract void DrawInsideSpriteBatch();        

        public void DrawOutsideSpriteBatch()
        {
            sprite_batch.Begin();

            DrawInsideSpriteBatch();

            sprite_batch.End();
        }

        public void DrawInsideSpriteBatch(float alpha)
        {
            this.alpha = alpha;

            DrawInsideSpriteBatch();

            this.alpha = 1.0f;
        }

        #endregion

        #region Events Delegate

        public void OnTap(Vector2 tap_position)
        { 
            if (rectangle.Contains((int)tap_position.X, (int)tap_position.Y) && OnPress != null)
                OnPress(this);
        }

        #endregion
    }

    public class LabelButton : MenuEntry
    {
        #region Fields

        Color color, shadow_color;
        Vector2 shadow_position;
        SpriteFont font;
        string label;

        #endregion

        #region Constructors

        public LabelButton(SpriteBatch sprite_batch, SpriteFont font, Vector2 position, Color color, Color shadow_color, string label)
        {
            Vector2 label_size = font.MeasureString(label);

            this.color = color;
            this.shadow_color = shadow_color;
            this.font = font;
            this.sprite_batch = sprite_batch;
            this.label = label;
            this.position = position;
            this.shadow_position = position + Vector2.One * 2.0f;
            this.rectangle = new Rectangle((int)position.X, (int)position.Y, (int)label_size.X, (int)label_size.Y);            
        }

        public LabelButton(SpriteBatch sprite_batch, SpriteFont font, Vector2 position, Color color, string label)
            : this(sprite_batch, font, position, color, Color.Transparent, label)
        { }

        public LabelButton(SpriteBatch sprite_batch, SpriteFont font, Vector2 position, Color color, Color shadow_color, string label, int padding)
            : this(sprite_batch, font, position, color, shadow_color, label)
        {
            rectangle.X -= padding;
            rectangle.Y -= padding;
            rectangle.Width += padding * 2;
            rectangle.Height += padding * 2;
        }

        public LabelButton(SpriteBatch sprite_batch, SpriteFont font, Vector2 position, Color color, string label, int padding)
            : this(sprite_batch, font, position, color, Color.Transparent, label, padding)
        { }

        #endregion

        #region Draw Methods

        public override void DrawInsideSpriteBatch()
        {
            sprite_batch.DrawString(font, label, shadow_position, shadow_color);
            sprite_batch.DrawString(font, label, position, color);
        }

        #endregion

        #region Proprieties

        #endregion
    }

    public class TextureButton : MenuEntry
    {
        #region Fields

        Color color;
        Texture2D texture;

        #endregion

        #region Constructors

        public TextureButton(SpriteBatch sprite_batch, Texture2D texture, Vector2 position, Color color)
        {
            this.color = color;
            this.sprite_batch = sprite_batch;
            this.position = position;
            this.rectangle = new Rectangle((int)position.X, (int)position.Y, texture.Width, texture.Height);
            this.texture = texture;
        }

        public TextureButton(SpriteBatch sprite_batch, Texture2D texture, Vector2 position)
            :this(sprite_batch, texture, position, Color.White)
        { }

        public TextureButton(SpriteBatch sprite_batch, Texture2D texture, Vector2 position, Color color, int padding)
            : this(sprite_batch, texture, position, color)
        {
            rectangle.X -= padding;
            rectangle.Y -= padding;
            rectangle.Width += padding * 2;
            rectangle.Height += padding * 2;
        }

        public TextureButton(SpriteBatch sprite_batch, Texture2D texture, Vector2 position, int padding)
            : this(sprite_batch, texture, position, Color.White, padding)
        { }

        #endregion

        #region Draw Methods

        public override void DrawInsideSpriteBatch()
        {
            sprite_batch.Draw(texture, rectangle, color * alpha);
        }

        #endregion

        #region Proprieties

        #endregion
    }

    public class BoxedLabelButton : MenuEntry
    {
        #region Fields

        Color color, shadow_color, box_color;
        Vector2 shadow_position, box_position;
        Texture2D box;
        SpriteFont font;
        string label;

        #endregion

        #region Constructors

        public BoxedLabelButton(SpriteBatch sprite_batch, Texture2D box, Vector2 box_position, Color box_color, SpriteFont font, 
            Vector2 label_offset, string label, Color color, Color shadow_color)
        {
            Vector2 label_size = font.MeasureString(label);

            this.box = box;
            this.box_color = box_color;
            this.box_position = box_position;
            this.color = color;
            this.shadow_color = shadow_color;
            this.font = font;
            this.sprite_batch = sprite_batch;
            this.label = label;
            this.position = new Vector2(box_position.X + (box.Width / 2.0f - label_size.X / 2.0f), 
                box_position.Y + (box.Height / 2.0f - label_size.Y / 2.0f)) + label_offset;
            this.shadow_position = position + Vector2.One * 2.0f;
            this.rectangle = new Rectangle((int)box_position.X, (int)box_position.Y, box.Width, box.Height);
        }

        public BoxedLabelButton(SpriteBatch sprite_batch, Texture2D box, Vector2 box_position, SpriteFont font,
            Vector2 label_offset, string label, Color color, Color shadow_color)
            : this(sprite_batch, box, box_position, Color.White, font, label_offset, label, color, shadow_color)
        { }

        public BoxedLabelButton(SpriteBatch sprite_batch, Texture2D box, Vector2 box_position, SpriteFont font,
            string label, Color color, Color shadow_color)
            : this(sprite_batch, box, box_position, Color.White, font, Vector2.Zero, label, color, shadow_color)
        { }

        public BoxedLabelButton(SpriteBatch sprite_batch, Texture2D box, Vector2 box_position, SpriteFont font, 
            string label, Color color)
            : this(sprite_batch, box, box_position, Color.White, font, Vector2.Zero, label, color, Color.Transparent)
        { }

        public BoxedLabelButton(SpriteBatch sprite_batch, Texture2D box, Vector2 box_position, SpriteFont font,
            Vector2 label_offset, string label, Color color)
            : this(sprite_batch, box, box_position, Color.White, font, label_offset, label, color, Color.Transparent)
        { }

        #endregion

        #region Draw Methods

        public override void DrawInsideSpriteBatch()
        {
            sprite_batch.Draw(box, rectangle, box_color * alpha);
            sprite_batch.DrawString(font, label, shadow_position, shadow_color * alpha);
            sprite_batch.DrawString(font, label, position, color * alpha);
        }

        #endregion

        #region Proprieties

        public string Label
        {
            get { return label; }
        }

        #endregion
    }


    public class BoxedLabelScrollableButton : MenuEntry
    {
        #region Fields

        Color color, shadow_color, box_color;
        Vector2 shadow_position, box_position;
        Texture2D box;
        SpriteFont font;
        string label;

        #endregion

        #region Constructors

        public BoxedLabelScrollableButton(SpriteBatch sprite_batch, Texture2D box, Vector2 box_position, Color box_color, SpriteFont font,
            Vector2 label_offset, string label, Color color, Color shadow_color)
        {
            Vector2 label_size = font.MeasureString(label);

            this.box = box;
            this.box_color = box_color;
            this.box_position = box_position;
            this.color = color;
            this.shadow_color = shadow_color;
            this.font = font;
            this.sprite_batch = sprite_batch;
            this.label = label;
            this.position = new Vector2(box_position.X + (box.Width / 2.0f - label_size.X / 2.0f),
                box_position.Y + (box.Height / 2.0f - label_size.Y / 2.0f)) + label_offset;
            this.shadow_position = position + Vector2.One * 2.0f;
            this.rectangle = new Rectangle((int)box_position.X, (int)box_position.Y, box.Width, box.Height);
        }

        public BoxedLabelScrollableButton(SpriteBatch sprite_batch, Texture2D box, Vector2 box_position, SpriteFont font,
            Vector2 label_offset, string label, Color color, Color shadow_color)
            : this(sprite_batch, box, box_position, Color.White, font, label_offset, label, color, shadow_color)
        { }

        public BoxedLabelScrollableButton(SpriteBatch sprite_batch, Texture2D box, Vector2 box_position, SpriteFont font,
            string label, Color color, Color shadow_color)
            : this(sprite_batch, box, box_position, Color.White, font, Vector2.Zero, label, color, shadow_color)
        { }

        public BoxedLabelScrollableButton(SpriteBatch sprite_batch, Texture2D box, Vector2 box_position, SpriteFont font,
            string label, Color color)
            : this(sprite_batch, box, box_position, Color.White, font, Vector2.Zero, label, color, Color.Transparent)
        { }

        public BoxedLabelScrollableButton(SpriteBatch sprite_batch, Texture2D box, Vector2 box_position, SpriteFont font,
            Vector2 label_offset, string label, Color color)
            : this(sprite_batch, box, box_position, Color.White, font, label_offset, label, color, Color.Transparent)
        { }

        #endregion

        #region Draw Methods

        public override void DrawInsideSpriteBatch()
        {
            var o_rectangle = rectangle;
            o_rectangle.Location = new Point((int)scrollOffset.X + o_rectangle.Location.X, (int)scrollOffset.Y + o_rectangle.Location.Y);
            var o_shadow_position = shadow_position + scrollOffset;
            var o_position = position + scrollOffset;
            sprite_batch.Draw(box, o_rectangle, box_color * alpha);
            sprite_batch.DrawString(font, label, o_shadow_position, shadow_color * alpha);
            sprite_batch.DrawString(font, label, o_position, color * alpha);
        }

        #endregion

        #region Proprieties

        public string Label
        {
            get { return label; }
        }

        #endregion
    }
}
